/***********************************************\
|	"Warehouse's database, Alexander Yushkov"	|
|	- connects.cpp - realization of functoins	|
|		from connects.h. All the output from	|
|		this file is being packed to strings by	|
|		stringstream methods and outputed by	|
|		functions from main.cpp.				|
\***********************************************/

#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
#include <iomanip>
#include "connects.h"

namespace lmf {

using namespace std;

vistream vcin('\n');

List extract_base(Base& base_in)
{
    List out_list(base_in.dat_size);
    if(!base_in.fsFile.is_open())
	{
		line("The base is not opened");
		border();
		return out_list;
	}
    char* buf=new char[base_in.dat_size];
    base_in.fsFile.seekp(0L,ios::beg);
    while(base_in.fsFile.read(buf,base_in.dat_size))
    	out_list.push_back(buf);
	base_in.fsFile.clear();
    delete[] buf;
    return out_list;
}

List_s extract_log(Base& base_in)
{
    List_s out_list(base_in.dat_size);
    if(!base_in.fsFile.is_open())
	{
		line("The base is not opened");
		border();
		return out_list;
	}
    char* buf=new char[base_in.dat_size];
    base_in.fsFile.seekp(0L,ios::beg);
    while(base_in.fsFile.read(buf,base_in.dat_size))
    	out_list.push_back(buf);
	base_in.fsFile.clear();
    delete[] buf;
    return out_list;
}

void dump_base(Base& base_out,List& in_list)
{
	if(base_out.fsFile.is_open())
	{
		base_out.fsFile.close();
		base_out.fsFile.open(base_out.cName,std::ios::in | std::ios::out | std::ios::binary | std::ios::trunc);
	}
	else
	{
		line("The base is not opened");
		border();
		return;
	}
	char* buf=new char[base_out.dat_size];
	base_out.fsFile.seekp(0L,ios::end);
	for(List::iterator i=in_list.begin();i!=in_list.end();++i)
		base_out.fsFile.write(*i,base_out.dat_size);
	delete[] buf;
	return;
}

void dump_log(Base& base_out,List_s& in_list)
{
	if(base_out.fsFile.is_open())
	{
		base_out.fsFile.close();
		base_out.fsFile.open(base_out.cName,std::ios::in | std::ios::out | std::ios::binary | std::ios::trunc);
	}
	else
	{
		line("The base is not opened");
		border();
		return;
	}
	char* buf=new char[base_out.dat_size];
	base_out.fsFile.seekp(0L,ios::end);
	for(List_s::iterator i=in_list.begin();i!=in_list.end();++i)
		base_out.fsFile.write(*i,base_out.dat_size);
	delete[] buf;
	return;
}

void add_group(List& to_list)
try
{
	int day;
	int mounth;
	int year;
	double count=0;
	double price_buy=0;
	double price_sell=0;

	line("Enter parameters:");
	border();
	ask("Enter count:");
	vcin.set_del('\n');
	vcin >> count;
	ask("Enter date:");
	vcin.set_del(' ');
	vcin >> day;
	vcin >> mounth;
	vcin.set_del('\n');
	vcin >> year;
	ask("Enter price bought:");
	vcin >> price_buy;
	ask("Enter price to sell:");
	try
	{
		vcin >> price_sell;
	}
	catch(vistream::empty& e)
	{
		price_sell=price_buy;
	}
	border();

	Group adding(Date(day,mounth,year),count,price_buy,price_sell);

	char* buf=new char[Group::size];
	serialize(adding,buf);

	to_list.push_back(buf);

	delete[] buf;
	return;
}
catch(int& e)
{
	line("Bad date");
	border();
}
catch(...)
{
	border();
	line("Bad parameters");
	border();
}

void get_group(List& list,List_s& log)
try
{
	int day=0;
	int mounth=0;
	int year=0;
	double count=0;
	double price=0;
	t_mode mode=FULL;

	line("Enter parameters:");
	border();
	ask("Enter count:");
	vcin.set_del('\n');
	vcin >> count;
	ask("Enter date:");
	try
	{
		vcin.set_del(' ');
		vcin >> day;
		vcin >> mounth;
		vcin.set_del('\n');
		vcin >> year;
	}
	catch(vistream::empty& e)
	{
		mode|=NODATE;
	}
	ask("Enter price:");
	try
	{
		vcin.set_del('\n');
		vcin >> price;
	}
	catch(vistream::empty& e)
	{
		mode|=NOPRICE;
	}
	border();

	switch(mode)
	{
		case FULL:
			get_group(list,log,count,Date(day,mounth,year),price);
			break;
		case NODATE:
			get_group(list,log,count,price);
			break;
		case NOPRICE:
			get_group(list,log,count,Date(day,mounth,year));
			break;
		case NOTHING:
			get_group(list,log,count);
			break;
	}
}
catch(...)
{
	border();
	line("Bad parameters");
	border();
}

void get_group(List& list,List_s& log,double count)
{
	if(list.size()<0)
	{
		line("Empty store");
		border();
		return;
	}
	Group temp;
	deserialize(*list.begin(),temp);
	if(temp.count<count || count <0)
	{
		stringstream strbuf(stringstream::in | stringstream::out);
		char str[56];
		strbuf	<< "Not enougth items in the first group, " << temp.count << " available";
		strbuf.getline(str,55,-1);
		strbuf.ignore(-1);
		strbuf.clear();
		line(str);
		border();
		return;
	}
	Record rec(*temp.date_in,count,count*temp.price_sell,count*(temp.price_sell-temp.price_buy));
	char* rec_buf=new char[sizeof(Record)];
	serialize(rec,rec_buf);
	log.push_back(rec_buf);
	if(temp.count==count)
	{
		list.remove(list.begin());
	}
	else
	{
		temp.count-=count;
		serialize(temp,*list.begin());
	}
	delete[] rec_buf;
	return;
}

void get_group(List& list,List_s& log,double count,Date date)
{
	if(list.size()<0)
	{
		line("Empty store");
		border();
		return;
	}
	Group temp;
	List::iterator i;
	for(i=list.begin();i!=list.end();++i)
	{
		deserialize(*i,temp);
		if(*temp.date_in==date)
			break;
	}
	if(i==list.end())
	{
		line("No such group in the base");
		border();
		return;
	}
	if(temp.count<count || count<0)
	{
		stringstream strbuf(stringstream::in | stringstream::out);
		char str[56];
		strbuf	<< "Wrong count, " << temp.count << " available in the group";
		strbuf.getline(str,55,-1);
		strbuf.ignore(-1);
		strbuf.clear();
		line(str);
		border();
		return;
	}
	Record rec(*temp.date_in,count,count*temp.price_sell,count*(temp.price_sell-temp.price_buy));
	char* rec_buf=new char[sizeof(Record)];
	serialize(rec,rec_buf);
	log.push_back(rec_buf);
	if(temp.count==count)
	{
		list.remove(i);
	}
	else
	{
		temp.count-=count;
		serialize(temp,*i);
	}
	delete[] rec_buf;
	return;
}

void get_group(List& list,List_s& log,double count,double price)
{
	if(list.size()<0)
	{
		line("Empty store");
		border();
		return;
	}
	Group temp;
	deserialize(*list.begin(),temp);
	if(temp.count<count || count<0)
	{
		stringstream strbuf(stringstream::in | stringstream::out);
		char str[56];
		strbuf	<< "Wrong count, " << temp.count << " available in the group";
		strbuf.getline(str,55,-1);
		strbuf.ignore(-1);
		strbuf.clear();
		line(str);
		border();
		return;
	}
	if(temp.price_sell>price)
	{
		stringstream strbuf(stringstream::in | stringstream::out);
		char str[56];
		strbuf << "The price is too low, it should be " << temp.price_sell << " at least";
		strbuf.getline(str,55,-1);
		strbuf.ignore(-1);
		strbuf.clear();
		line(str);
		border();
		return;
	}
	Record rec(*temp.date_in,count,count*price,count*(price-temp.price_buy));
	char* rec_buf=new char[sizeof(Record)];
	serialize(rec,rec_buf);
	log.push_back(rec_buf);
	if(temp.count==count)
	{
		list.remove(list.begin());
	}
	else
	{
		temp.count-=count;
		serialize(temp,*list.begin());
	}
	delete[] rec_buf;
	return;
}

void get_group(List& list,List_s& log,double count,Date date,double price)
{
	if(list.size()<0)
	{
		line("Empty store");
		border();
		return;
	}
	Group temp;
	List::iterator i;
	for(i=list.begin();i!=list.end();++i)
	{
		deserialize(*i,temp);
		if(*temp.date_in==date)
			break;
	}
	if(i==list.end())
	{
		line("No such group in the base");
		border();
		return;
	}
	if(temp.count<count || count<0)
	{
		stringstream strbuf(stringstream::in | stringstream::out);
		char str[56];
		strbuf	<< "Wrong count, " << temp.count << " available in the group";
		strbuf.getline(str,55,-1);
		strbuf.ignore(-1);
		strbuf.clear();
		line(str);
		border();
		return;
	}
	if(temp.price_sell>price)
	{
		stringstream strbuf(stringstream::in | stringstream::out);
		char str[56];
		strbuf << "The price is too low, it should be " << temp.price_sell << " at least";
		strbuf.getline(str,55,-1);
		strbuf.ignore(-1);
		strbuf.clear();
		line(str);
		border();
		return;
	}
	Record rec(*temp.date_in,count,count*temp.price_sell,count*(temp.price_sell-temp.price_buy));
	char* rec_buf=new char[sizeof(Record)];
	serialize(rec,rec_buf);
	log.push_back(rec_buf);
	if(temp.count==count)
	{
		list.remove(i);
	}
	else
	{
		temp.count-=count;
		serialize(temp,*i);
	}
	delete[] rec_buf;
	return;
}

void print(List& list)
{
	Group temp;
	line("Now in the storage:");
	border();
	stringstream strbuf(stringstream::in | stringstream::out);
	char str[56];
	strbuf	<< left
			<< setw(11) << "Date" << setw(2) << '|'
			<< setw(12) << "Count" << setw(2) << '|'
			<< setw(12) << "Price bought" << setw(2) << '|'
			<< setw(13) << "Price to sell";
	strbuf.getline(str,55,-1);
	strbuf.ignore(-1);
	strbuf.clear();
	line(str);
	border();
	for(List::iterator iter=list.begin();iter!=list.end();++iter)
	{
		deserialize(*iter,temp);
		strbuf	<< right;
		strbuf 	<< setfill('0') << setw(2) << temp.date_in->day << '-'
				<< setfill('0') << setw(2) << temp.date_in->mounth << '-'
				<< temp.date_in->year << setfill(' ') << setw(2) << '|'
				<< setw(12) << temp.count << setw(2) << '|'
				<< setw(12) << temp.price_buy << setw(2) << '|'
				<< setw(14) << temp.price_sell;
		strbuf.getline(str,55,-1);
		strbuf.ignore(-1);
		strbuf.clear();
		line(str);
	}
	border();
	return;
}

void print(List_s& log)
{
	Record temp;
	line("Sales's history:");
	border();
	stringstream strbuf(stringstream::in | stringstream::out);
	char str[56];
	strbuf	<< left
			<< setw(11) << "Date" << setw(2) << '|'
			<< setw(12) << "Count" << setw(2) << '|'
			<< setw(12) << "Price sold" << setw(2) << '|'
			<< setw(13) << "Profit";
	strbuf.getline(str,55,-1);
	strbuf.ignore(-1);
	strbuf.clear();
	line(str);
	border();
	for(List_s::iterator iter=log.begin();iter!=log.end();++iter)
	{
		deserialize(*iter,temp);
		strbuf	<< right;
		strbuf 	<< setfill('0') << setw(2) << temp.date_sold.day << '-'
				<< setfill('0') << setw(2) << temp.date_sold.mounth << '-'
				<< temp.date_sold.year << setfill(' ') << setw(2) << '|'
				<< setw(12) << temp.count << setw(2) << '|'
				<< setw(12) << temp.price << setw(2) << '|'
				<< setw(14) << temp.profit;
		strbuf.getline(str,55,-1);
		strbuf.ignore(-1);
		strbuf.clear();
		line(str);
	}
	border();
}

void stat_full(List& list,List_s& log)
{
	print(list);
	Group gr_temp;
	double total_spent=0;
	for(List::iterator iter=list.begin();iter!=list.end();++iter)
	{
		deserialize(*iter,gr_temp);
		total_spent+=gr_temp.price_buy*gr_temp.count;
	}
	Record rec_temp;
	double total_profit=0;
	for(List_s::iterator iter=log.begin();iter!=log.end();++iter)
	{
		deserialize(*iter,rec_temp);
		total_profit+=rec_temp.profit;
	}
	stringstream strbuf(stringstream::in | stringstream::out);
	char str[56];
	strbuf << "For: " << total_spent << " totally";
	strbuf.getline(str,55,-1);
	strbuf.ignore(-1);
	strbuf.clear();
	line(str);
	strbuf << "Total profit: " << total_profit;
	strbuf.getline(str,55,-1);
	strbuf.ignore(-1);
	strbuf.clear();
	line(str);
	border();
	return;
}

void stat_range(List& list,List_s& log)
try
{
	int day,mounth,year;
	line("Enter the interval");
	border();
	ask("Enter the left bound:");
	vcin.set_del(' ');
	vcin >> day >> mounth;
	vcin.set_del('\n');
	vcin >> year;
	Date one(day,mounth,year);
	ask("Enter the right bound:");
	vcin.set_del(' ');
	vcin >> day >> mounth;
	vcin.set_del('\n');
	vcin >> year;
	Date two(day,mounth,year);

	border();

	Group gr_temp;
	List sub_list(Group::size);
	for(List::iterator iter=list.begin();iter!=list.end();++iter)
	{
		deserialize(*iter,gr_temp);
		if(*gr_temp.date_in>=one && *gr_temp.date_in<=two)
			sub_list.push_back(*iter);
	}
	Record rec_temp;
	List_s sub_log(sizeof(Record));
	for(List_s::iterator iter=log.begin();iter!=log.end();++iter)
	{
		deserialize(*iter,rec_temp);
		if(rec_temp.date_sold>=one && rec_temp.date_sold<=two)
			sub_log.push_back(*iter);
	}

	print(sub_list);
	double total_spent=0;
	for(List::iterator iter=sub_list.begin();iter!=sub_list.end();++iter)
	{
		deserialize(*iter,gr_temp);
		total_spent+=gr_temp.price_buy*gr_temp.count;
	}
	double total_profit=0;
	for(List_s::iterator iter=sub_log.begin();iter!=sub_log.end();++iter)
	{
		deserialize(*iter,rec_temp);
		total_profit+=rec_temp.profit;
	}

	stringstream strbuf(stringstream::in | stringstream::out);
	char str[56];
	strbuf << "For: " << total_spent << " totally";
	strbuf.getline(str,55,-1);
	strbuf.ignore(-1);
	strbuf.clear();
	line(str);
	strbuf << "Total profit: " << total_profit;
	strbuf.getline(str,55,-1);
	strbuf.ignore(-1);
	strbuf.clear();
	line(str);
	border();
	return;
}
catch(...)
{
	border();
	line("Bad date");
	border();
	return;
}

}
